package darknet.core.impl;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetAddress;

import darknet.core.impl.friend.FriendManagerImpl;
import darknet.core.impl.net.NetworkManagerImpl;
import darknet.application.chat.impl.net.ChatProtocol;
import darknet.core.spec.Facade;
import darknet.core.spec.friend.FriendManager;
import darknet.core.spec.net.NetworkManager;
import darknet.application.chat.spec.ChatApplication;
import darknet.application.filesharing.impl.net.FileSharingProtocol;
import darknet.application.filesharing.spec.FileSharingApplication;
import darknet.core.impl.net.NodeImpl;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.Map;

/**
 * Facade implementation
 * 
 * @author Yoyo
 */
public class FacadeImpl implements Facade {

    /** Friend manager */
    private FriendManagerImpl friend = null;

    /** Network manager */
    private NetworkManager network = null;

    /** Chat application */
    private ChatApplication chat = null;

    /** File sharing application */
    private FileSharingApplication fileSharing = null;

    /**
     * Initialise a new instance of a Facade.
     * 
     * If username.keystore don't exist, a new friend manager and a new 
     * network manager is create.
     * 
     * @param workingDirectory The directory containing the keystore
     * @param username		User name
     * @param password		User Password
     * @param address		Node external address
     * @param port		Node external port
     * @throws IOException 
     * @throws FileNotFoundException 
     */
    public FacadeImpl(String workingDirectory,
            String username, String password,
            String address, int port)
            throws FileNotFoundException, IOException {

        if (workingDirectory == null || workingDirectory.length() == 0) {
            throw new IllegalArgumentException("working directory is invalid");
        }
        if (username == null | username.length() == 0) {
            throw new IllegalArgumentException("username is invalid");
        }

        // Generate or restaure friend manager.
        File keystoreFile = new File(
                workingDirectory + File.separator + username + ".keystore");
        if (keystoreFile.exists()) {

            friend = FriendManagerImpl.restaureFriendManager(
                    new File(workingDirectory), username, password);

        } else {

            friend = FriendManagerImpl.generateFriendManager(
                    new File(workingDirectory), username, password);
        }

        // Create new network manager.
        Map<String, NodeImpl> nodes = null;
        File nodeListFile = new File(
                workingDirectory + File.separator + username + ".nodelist");
        if (nodeListFile.exists()) {
            try {
                ObjectInputStream in = new ObjectInputStream(
                        new FileInputStream(nodeListFile));
                nodes = (Map<String, NodeImpl>) in.readObject();
                in.close();
            } catch (FileNotFoundException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }

        network = new NetworkManagerImpl(
                friend, port, InetAddress.getByName(address), nodes);

        // TODO Load applications via plugin detection, not directly into code.
        // Get Chat application
        chat = (ChatApplication) network.getApplication(
                ChatProtocol.getCurrent());
        fileSharing =  (FileSharingApplication) network.getApplication(
                FileSharingProtocol.getCurrent());
    }

    @Override
    public FriendManager getFriendManager() {
        return friend;
    }

    @Override
    public NetworkManager getNetworkManager() {
        return network;
    }

    @Override
    public ChatApplication getChatApplication() {
        return chat;
    }

    @Override
    public FileSharingApplication getFileSharingApplication() {
        return fileSharing;
    }
}
